package dataStructures.list;

import java.util.Iterator;

/**
 *
 * Fully Tested: Yes
 * Fully Documented: Yes
 * Created: 2011
 * Last Modified: Nov 16, 2011
 * @author Shimu
 */
public class SinglelyLinkedList<T> implements Iterable<T> {

    /** The size of the Queue */
    private int size;

    private SinglelyLinkedNode<T> first, last;

    public SinglelyLinkedList() {
        this.size = 0;
        this.first = null;
        this.last = null;
    }

    public SinglelyLinkedList(T firstData) {
        this(new SinglelyLinkedNode<T>(firstData));
    }

    public SinglelyLinkedList(SinglelyLinkedNode<T> firstNode) {
        this.size = 0;
        this.first = firstNode;
        this.last = firstNode;
    }

    public SinglelyLinkedNode<T> getFirst() {
        return this.first;
    }

    /**
     * Adds an item to the front of the LinkedList.
     * @param data
     */
    public void addFirst(T data) {
        SinglelyLinkedNode<T> oldFirst = first;
        first = new SinglelyLinkedNode<T>(data, oldFirst);
        size++;
    }

    /**
     * Adds an item to the back of the LinkedList.
     * @param data
     */
    public final void addLast(T data) {
        SinglelyLinkedNode<T> newNode = new SinglelyLinkedNode<T>(data);
        if (first == null) {
            first = newNode;
            first.next = last;
        } else if (last == null) {
            last = newNode;
            first.next = last;
        } else {
            last.next = newNode;
            last = last.next;
        }
        size++;
    }

    /**
     * Returns and removes an item from the front of the LinkedList.
     * Returns null if the item at the front of the LinkedList is null or
     * if the LinkedList is empty.
     *
     * @return the item at the front of the LinkedList
     */
    public T removeFirst() {
        if (first == null) {
            return null;
        } else {
            T returnData = first.data;
            first = first.next;
            size--;
            if (first == null) {
                last = null;
            }
            return returnData;
        }
    }

    /**
     * Returns true if this LinkedList has no more elements, false otherwise.
     * @return true if this LinkedList is empty.
     */
    public boolean isEmpty() {
        return (size == 0);
    }

    /**
     * Returns the number of elements in this LinkedList.
     * @return the size of this LinkedList.
     */
    public int getSize() {
        return this.size;
    }
   
    /**
     * Prints the content of this SinglelyLinkedList
     */
    public void printContent() {
        Iterator<T> iterator = this.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }

    /**
     * Returns a SinglelyLinkedList that is a sublist of this
     * SinglelyLinkedList from index 0 to index endIndex - 1.
     *
     * @param endIndex
     * @return a sublist of this list
     */
    //public SinglelyLinkedList<T> getSubList(int endIndex){
    //}
    public Iterator<T> iterator() {
        class SinglelyLinkedListIterator implements Iterator<T> {

            private SinglelyLinkedNode<T> current;

            private SinglelyLinkedListIterator() {
                this.current = first;
            }

            public boolean hasNext() {
                return (current != null);
            }

            public T next() {
                T returnData = current.data;
                current = current.next;
                return returnData;
            }

            public void remove() {
            }
        }

        return new SinglelyLinkedListIterator();
    }
}
